package org.newlucene.core.index;

import java.io.IOException;

import org.newlucene.core.document.Document;
import org.newlucene.core.store.Directory;

final class SegmentsReader extends IndexReader 
{
	protected SegmentReader[] readers;
	protected int[] starts;			  // 1st docno for each segment
	private int maxDoc = 0;
	private int numDocs = -1;

	SegmentsReader(Directory directory, SegmentReader[] r) throws IOException 
	{
		super(directory);
		readers = r;
		starts = new int[readers.length + 1];	  // build starts array
		for (int i = 0; i < readers.length; i++) 
		{
			starts[i] = maxDoc;
			maxDoc += readers[i].maxDoc();		  // compute maxDocs
		}
		starts[readers.length] = maxDoc;
	}

	public synchronized final int numDocs() 
	{
		if (numDocs == -1)			  // check cache
		{
			int n = 0;				  // cache miss--recompute
			for (int i = 0; i < readers.length; i++)
			{
				n += readers[i].numDocs();		  // sum from readers
			}
			numDocs = n;
		}
		return numDocs;
	}

	public final int maxDoc() 
	{
		return maxDoc;
	}

	public final Document document(int n) throws IOException 
	{
		int i = readerIndex(n);			  // find segment num
		return readers[i].document(n - starts[i]);	  // dispatch to segment reader
	}

	public final boolean isDeleted(int n) 
	{
		int i = readerIndex(n);			  // find segment num
		return readers[i].isDeleted(n - starts[i]);	  // dispatch to segment reader
	}

	synchronized final void doDelete(int n) throws IOException 
	{
		numDocs = -1;				  // invalidate cache
		int i = readerIndex(n);			  // find segment num
		readers[i].doDelete(n - starts[i]);		  // dispatch to segment reader
	}

	// find reader for doc n
	private final int readerIndex(int n)
	{
		int lo = 0;					  // search starts array
		int hi = readers.length - 1;		  // for first element less
						  // than n, return its index
		while (hi >= lo) 
		{
			int mid = (lo + hi) >> 1;
			int midValue = starts[mid];
			if (n < midValue)
			{
				hi = mid - 1;
			}
			else if (n > midValue)
			{
				lo = mid + 1;
			}
			else
			{
				return mid;
			}
		}
		return hi;
	}

	public final int docCount(Term t) throws IOException 
	{
		int total = 0;				  // sum freqs in segments
		for (int i = 0; i < readers.length; i++)
		{
			total += readers[i].docCount(t);
		}
		return total;
	}

	public final TermPostings termPostings() throws IOException 
	{
		return new SegmentsTermPostings(readers, starts);
	}

	final synchronized void doClose() throws IOException 
	{
		for (int i = 0; i < readers.length; i++)
		{
			readers[i].close();
		}
	}
}